home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-11 | 11.7 KB | 470 lines | [TEXT/MMCC] |
- /*================================================================================
- EventHandler.c
-
- ©1991-4 Greg Anderson
- greggor@apple.com
-
- This code handles the main macintosh event loop
- ================================================================================*/
- #include <EPPC.h>
- #include <AppleEvents.h>
- #include <Errors.h>
-
- #include "EventHandler.h"
- #include "NextEvent.h"
- #include "MenuHandler.h"
- #include "WindowHandler.h"
-
- #include "Main.h"
- #include "SetTypesDialog.h"
-
- //#include "TEUtilities.h"
- #include "MacUtilities.h"
- #include "DialogUtilities.h"
- #include "ReportError.h"
- #include "Exceptions.h"
-
- //
- // Prototypes for private functions:
- //
- void Idle(EventRecord* nullEvent);
-
- void ProcessModelessDialog( EventRecord* theEvent );
- Boolean ProcessMouseEvent( EventRecord* theEvent );
- void SetupCursorShape( Point theMouse, RgnHandle mouseRgn );
-
- //----------------------------------------------------------------------------------------
- // Idle:
- //----------------------------------------------------------------------------------------
- void Idle(EventRecord* nullEvent)
- {
- FrontWindowHandler()->Idle(nullEvent);
- } // Idle
-
- //----------------------------------------------------------------------------------------
- // HandleEvents:
- //
- // Main event processor
- //----------------------------------------------------------------------------------------
- void HandleEvents( RgnHandle mouseRegion )
- {
- EventRecord theEvent;
- Boolean isDialogEvent;
- long theSleep;
- Point mouse;
- char keyPressed;
- OSErr err = noErr;
-
- //
- // This routine watches the cursor as it moves across the
- // window & changes its shape as necessary.
- //
- GetMouse( &mouse );
- LocalToGlobal( &mouse );
- SetupCursorShape( mouse, mouseRegion);
-
- //
- // Get the next event, whatever type it might be.
- //
- // 'NextEvent' calls either GetNextEvent or WaitNextEvent
- // (preferably the later). It does some processing
- // to make deactivate, suspend, resume and mouse-moved
- // events easier to interpret.
- //
- // If 'GetNextEvent' is called, mouse-moved events are
- // simulated, so the same cursor-tracking code may be
- // used in multifinder and non-multifinder environments.
- //
- theSleep = GetCaretTime() >> 1;
- isDialogEvent = NextEvent( everyEvent, &theEvent, theSleep, mouseRegion );
-
- #ifdef ShowMouseRgn
- SetPort(gWindowMgrPort);
- SetClip(gUniverseRgn);
- InvertRgn(mouseRegion);
- InvertRgn(mouseRegion);
- #endif
-
- //
- // It seems that the only way to do accurate mouse tracking
- // is to call SetupCursorShape before and after NextEvent.
- //
- // Passing nil as the mouseRgn prevents all of the complex region
- // calculations from being done twice.
- //
- SetupCursorShape( theEvent.where, nil );
-
- //
- // Set up a failure handler for commands that just cannot be completed
- //
- Try
- {
- Boolean eventHandled = false;
-
- //
- // Here is the dreaded Event Switch Statement.
- //
- // I should write a better event processor -- or better yet,
- // switch to MacApp. :>
- //
- // A word of warning for the unwary: NextEvent() mauls
- // theEvent.what, so some of the items in this switch statement
- // might be undefined if GetNextEvent or WaitNextEvent is
- // called directly. Activate, deactivate, suspend and resume
- // events are all mauled by NextEvent. See NextEvent.c for
- // code that detects these events (or better yet, include
- // NextEvent.c in your project and use this code as a sample,
- // and you'll be MultiFinder aware).
- //
- switch( theEvent.what )
- {
- //
- // First check for high-level events (e.g. AppleEvents)
- //
- case kHighLevelEvent:
- {
- AEProcessAppleEvent( &theEvent );
- eventHandled = true;
- break;
- }
-
- //
- // If the event is a mousedown event, theEvent.message is undefined,
- // but theEvent.where specifies where the mouse was located when the
- // button went down.
- //
- case mouseDown:
- {
- eventHandled = ProcessMouseEvent( &theEvent );
- break;
- }
-
- //
- // If the event is a keyDown or autoKey event, theEvent.message
- // contains the character code & key code of the key pressed
- // in its low word.
- //
- case autoKey:
- {
- //
- // Don't allow autokeys to work with menu equivalents
- //
- if( (theEvent.modifiers & cmdKey) != 0 )
- {
- eventHandled = true;
- break;
- }
- }
-
- case keyDown:
- {
- keyPressed = (char)(theEvent.message & charCodeMask);
-
- //
- // Handle command-key equivalents of menu functions
- //
- if( (theEvent.modifiers & cmdKey) != 0)
- {
- SetupMenuItems();
- ProcessMenuSelection( MenuKey(keyPressed) );
- eventHandled = true;
- }
- else
- {
- eventHandled = FrontWindowHandler()->KeyDown(&theEvent, keyPressed);
- }
-
- break;
- }
-
- //
- // If the event is an update event or an activate event,
- // theEvent.message contains a pointer to the window
- // receiving the event
- //
- case updateEvt:
- {
- GetWindowHandler((WindowPtr)(theEvent.message))->Update(&theEvent);
- break;
- }
-
- //
- // An activate event can mean that a window is being activated,
- // OR it could mean that a window is being deactivated.
- //
- // However, NextEvent decodes the event record and returns
- // 'deactivateEvt' if the event was a deactivate; this
- // simplifies this switch statement. Be careful when copying
- // this code--if you call WaitNextEvent directly, the
- // translation will not be done and this code won't work.
- //
- case activateEvt:
- {
- GetWindowHandler((WindowPtr)(theEvent.message))->Activate(&theEvent);
- break;
- }
-
- case deactivateEvt:
- {
- GetWindowHandler((WindowPtr)(theEvent.message))->Deactivate(&theEvent);
- break;
- }
-
- //
- // Suspend and resume events are treated like activate and
- // deactivate messages. (Note that FrontWindow() might
- // return nil; ActivateWindow and DeactivateWindow should
- // catch this and exit gracefully.)
- //
- // Note that NextEvent decodes app4Evt's and returns either
- // resumeEvt, suspendEvt or mouseMovedEvt.
- //
- case resumeEvt:
- {
- GetWindowHandler((WindowPtr)(theEvent.message))->Resume(&theEvent);
- break;
- }
-
- case suspendEvt:
- {
- GetWindowHandler((WindowPtr)(theEvent.message))->Suspend(&theEvent);
- break;
- }
-
- //
- // The mouseRegion is recalculated on every event,
- // so nothing special needs to be done on mouseMovedEvt.
- //
- case mouseMovedEvt:
- {
- break;
- }
- }
-
- //
- // Check for modeless dialog events & pass them to the
- // appropriate modeless dialog box.
- //
- // Do not pass events already handled above, though.
- //
- if( isDialogEvent && (eventHandled == false))
- {
- ProcessModelessDialog( &theEvent );
- }
-
- //
- // Do idle-type-stuff
- //
- Idle(&theEvent);
- }
- Catch(err)
- {
- if((err != eNoWindowHandler) && (err != userCanceledErr))
- {
- //
- // It would be nice if we had better error reporting
- //
- ReportError( "\pThe command could not be completed", err );
- }
- }
- } // HandleEvents
-
- //----------------------------------------------------------------------------------------
- // ProcessModelessDialog:
- //
- // Modeless-dialog event.
- //----------------------------------------------------------------------------------------
- void ProcessModelessDialog( EventRecord* theEvent )
- {
- DialogPtr theDialog;
- short itemHit;
-
- //
- // If the event is a modeless dialog event, pass it to
- // DialogSelect.
- //
- // If DialogSelect returns 'true', that indicates that
- // the user has interacted with the dialog in some way.
- // If this is the case, theDialog will point to the
- // dialog box in question, and itemHit will contain the
- // number of the item clicked on.
- //
- // We determine which dialog was clicked on by examining
- // a field in the record pointed to by the dialog's
- // refCon.
- //
- if( DialogSelect( theEvent, &theDialog, &itemHit ) )
- {
- //
- // Pass the event record and itemHit to the window handler
- //
- GetWindowHandler(theDialog)->DialogManagerEvent(theEvent, itemHit);
- }
- } // ProcessModelessDialog
-
- //----------------------------------------------------------------------------------------
- // ProcessMouseEvent:
- //
- // Mouse-click event.
- //
- // Strangely enough, theEvent->message doesn't tell us which window
- // was clicked on. The Macintosh toolbox function 'FindWindow' can
- // determine this for us, however.
- //----------------------------------------------------------------------------------------
- Boolean ProcessMouseEvent( EventRecord* theEvent )
- {
- WindowPtr whichWindow;
- Boolean eventHandled = false;
-
- switch( FindWindow( theEvent->where, &whichWindow ) )
- {
- case inMenuBar:
- {
- SetupMenuItems();
- ProcessMenuSelection( MenuSelect(theEvent->where) );
- eventHandled = true;
- break;
- }
-
- case inSysWindow:
- {
- SystemClick( theEvent,(WindowPtr)whichWindow );
- eventHandled = true;
- break;
- }
-
- case inContent:
- {
- //
- // If the window clicked on is not frontmost, make it frontmost.
- //
- if( whichWindow != FrontWindow() )
- {
- SelectWindow(whichWindow);
- eventHandled = true;
- }
- else
- {
- eventHandled = GetWindowHandler(whichWindow)->ContentClick(theEvent);
- }
- break;
- }
-
- case inDrag:
- {
- DragWindow( (WindowPtr)whichWindow,theEvent->where,&gUniverseRect);
- eventHandled = true;
- break;
- }
-
- case inGrow:
- {
- GetWindowHandler(whichWindow)->ResizeWindow(theEvent->where);
- eventHandled = true;
- break;
- }
-
- case inGoAway:
- {
- if( TrackGoAway(whichWindow,theEvent->where) )
- {
- //
- // We only have one window, so close it
- //
- GetWindowHandler(whichWindow)->CloseWindowByUser();
- }
- eventHandled = true;
- break;
- }
- }
- return eventHandled;
- } // ProcessMouseEvent
-
- //----------------------------------------------------------------------------------------
- // SetupCursorShape:
- //
- // Change the shape of the cursor based on its location
- //----------------------------------------------------------------------------------------
- void SetupCursorShape( Point theMouse, RgnHandle mouseRgn )
- {
- OSErr err = noErr;
-
- //
- // Try to set the shape of the cursor
- //
- Try
- {
- WindowPtr inWindow = nil;
- Rect tRect;
- Rect windowRect;
-
- //
- // Is there a window? If not, fail (error code is ignored, so it
- // doesn't matter what it is)
- //
- inWindow = FrontWindow();
- if(inWindow == nil)
- Throw(-1);
-
- SetPort(inWindow);
- GetGlobalWindowLocation(inWindow, &windowRect); // inWindow->port.portRect
-
- //
- // If the point is not inside the front window,
- // then set the cursor to an arrow, and set the mouse
- // region to the universe minus the space taken by
- // the front window
- //
- if(PtInRect(theMouse, &windowRect) == false)
- {
- ChangeCursor(0);
- if(mouseRgn != nil)
- {
- RectRgn(mouseRgn, &windowRect);
- XorRgn(mouseRgn, gUniverseRgn, mouseRgn);
- }
- }
- else
- {
- //
- // Do all of our work in local coordinates
- //
- GlobalToLocal(&theMouse);
-
- //
- // By default, the mouse region is a one-pixel region
- // that just surrounds the cursor. TWindowHandler::SetupCursorShape
- // may change this region to something else
- //
- SetRect(&tRect, theMouse.h, theMouse.v, theMouse.h + 1, theMouse.v + 1);
- if(mouseRgn != nil)
- RectRgn(mouseRgn, &tRect);
-
- //
- // If this window doesn't have a window handler, then
- // GetWindowHandler will fail. If SetupCursorShape
- // returns false, then the handler did not have a specific
- // shape to set the cursor to; set it to an arrow.
- //
- if(GetWindowHandler(inWindow)->SetupCursorShape(theMouse, mouseRgn) == false)
- ChangeCursor(0);
-
- //
- // Translate the region back to global coordinates
- //
- if(mouseRgn != nil)
- RgnToGlobal(mouseRgn);
- }
- }
- Catch(err)
- {
- //
- // If we couldn't handle the SetupCursorShape event, then
- // the cursor is an arrow everywhere
- //
- ChangeCursor(0);
- if(mouseRgn != nil)
- RectRgn(mouseRgn, &gUniverseRect);
- }
- } // SetupCursorShape
-